using System.Collections.Concurrent;
using System.Reflection;
using SharedKernel.Domain.Events;

namespace SharedKernel.Infrastructure.EventBus
{
    /// <summary>
    /// 内存事件总线实现
    /// </summary>
    public class InMemoryEventBus : IEventBus
    {
        private readonly ConcurrentDictionary<Type, List<Type>> _eventHandlers = new();
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serviceProvider">服务提供器</param>
        public InMemoryEventBus(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 发布事件
        /// </summary>
        public async Task PublishAsync<TEvent>(TEvent @event) where TEvent : DomainEvent
        {
            var eventType = typeof(TEvent);

            if (_eventHandlers.TryGetValue(eventType, out var handlers))
            {
                foreach (var handlerType in handlers)
                {
                    var handler = _serviceProvider.GetService(handlerType) as IEventHandler<TEvent>;
                    if (handler != null)
                    {
                        await handler.HandleAsync(@event);
                    }
                }
            }
        }

        /// <summary>
        /// 订阅事件
        /// </summary>
        public void Subscribe<TEvent, THandler>() where TEvent : DomainEvent
            where THandler : IEventHandler<TEvent>
        {
            var eventType = typeof(TEvent);
            var handlerType = typeof(THandler);

            _eventHandlers.AddOrUpdate(
                eventType,
                _ => new List<Type> { handlerType },
                (_, existingHandlers) =>
                {
                    if (!existingHandlers.Contains(handlerType))
                    {
                        existingHandlers.Add(handlerType);
                    }
                    return existingHandlers;
                });
        }

        /// <summary>
        /// 取消订阅事件
        /// </summary>
        public void Unsubscribe<TEvent, THandler>() where TEvent : DomainEvent
            where THandler : IEventHandler<TEvent>
        {
            var eventType = typeof(TEvent);
            var handlerType = typeof(THandler);

            if (_eventHandlers.TryGetValue(eventType, out var handlers))
            {
                handlers.Remove(handlerType);
                if (handlers.Count == 0)
                {
                    _eventHandlers.TryRemove(eventType, out _);
                }
            }
        }
    }
}